package work.mediway.mdm.biz.service.biz.impl;

import com.mediway.hos.app.base.seure.util.SecurityUtils;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import work.mediway.mdm.core.entity.TableForeignKey;
import work.mediway.mdm.core.enums.StatusWhetherEnum;
import work.mediway.mdm.biz.dto.biz.SsFieldPermDTO;
import work.mediway.mdm.biz.dto.dict.DictFieldDTO;
import work.mediway.mdm.core.constant.MdmConstant;
import work.mediway.mdm.biz.helper.BusinessDatabaseHelper;
import work.mediway.mdm.biz.service.biz.SsUserLinkFieldService;
import work.mediway.mdm.biz.service.biz.TableFieldService;
import work.mediway.mdm.biz.vo.biz.SsFieldPermVO;
import work.mediway.mdm.biz.vo.dict.DictFieldVO;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2022/7/15
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class TableFieldServiceImpl implements TableFieldService {

    private final BusinessDatabaseHelper businessDatabaseHelper;
    private final SsUserLinkFieldService userLinkFieldService;

    @Override
    public List<DictFieldVO> listDictFieldAll(DictFieldDTO dictFieldDTO, boolean showForeign) {
        List<DictFieldVO> result = CollUtil.newArrayList();
        Map<String, TableForeignKey> foreignMap = MapUtil.newHashMap();
        List<String> foreignList = CollUtil.newArrayList();
        List<DictFieldVO> column = getDictAllField(dictFieldDTO, foreignMap, foreignList);

        for (DictFieldVO vo : column) {
            if (CollUtil.contains(foreignList, vo.getFieldCode())) {
                vo.setFkTableName(foreignMap.get(vo.getFieldCode()).getFkTableName());
                vo.setFkColumnName(foreignMap.get(vo.getFieldCode()).getFkColumnName());
            }

            filterCodeOrDesc(dictFieldDTO, result, vo);

            // 字段存在外键时，新增一条其描述字段
            if (showForeign && CollUtil.contains(foreignList, vo.getFieldCode())) {
                dealForeignKey(result, foreignMap, vo);
            }
        }
        return result;
    }

    private void filterCodeOrDesc(DictFieldDTO dictFieldDTO, List<DictFieldVO> result, DictFieldVO vo) {
        if (StrUtil.isNotBlank(dictFieldDTO.getFieldCode()) || StrUtil.isNotBlank(dictFieldDTO.getFieldDesc())) {
            if (StrUtil.contains(vo.getFieldCode(), dictFieldDTO.getFieldCode()) || StrUtil.contains(vo.getFieldCode(), dictFieldDTO.getFieldDesc())
                    || StrUtil.contains(vo.getFieldDesc(), dictFieldDTO.getFieldCode()) || StrUtil.contains(vo.getFieldDesc(), dictFieldDTO.getFieldDesc())) {
                result.add(vo);
            }
        } else {
            result.add(vo);
        }
    }

    private List<DictFieldVO> getDictAllField(DictFieldDTO dictFieldDTO, Map<String, TableForeignKey> foreignMap, List<String> foreignList) {
        // 查询表的所有字段
        List<DictFieldVO> column = businessDatabaseHelper.getColumn(dictFieldDTO.getTableCode());
        // 查询表中存在外键关联的字段
        List<TableForeignKey> foreignKey = businessDatabaseHelper.getForeignKey(dictFieldDTO.getTableCode());
        for (TableForeignKey tableForeignKey : foreignKey) {
            foreignMap.put(tableForeignKey.getPkColumnName(), tableForeignKey);
            foreignList.add(tableForeignKey.getPkColumnName());
        }
        return column;
    }

    @Override
    public List<DictFieldVO> listDictField(DictFieldDTO dictFieldDTO, boolean showForeign) {
        List<DictFieldVO> result = CollUtil.newArrayList();
        Map<String, TableForeignKey> foreignMap = MapUtil.newHashMap();
        List<String> foreignList = CollUtil.newArrayList();
        List<DictFieldVO> column = getDictAllField(dictFieldDTO, foreignMap, foreignList);

        // 查询字段权限
        String userId = StrUtil.isNotBlank(dictFieldDTO.getUserId()) ? dictFieldDTO.getUserId() : SecurityUtils.getUserId();
        String roleId = StrUtil.isNotBlank(dictFieldDTO.getRoleId()) ? dictFieldDTO.getRoleId() : SecurityUtils.getSingleUserRoleId();
        SsFieldPermDTO permDTO = SsFieldPermDTO.build(dictFieldDTO.getTableCode(), userId, roleId);
        // 当前权限字段结果集
        List<SsFieldPermVO> listFieldPerm = this.userLinkFieldService.listFieldPerm(permDTO);
        List<String> fieldPerm = listFieldPerm.stream().map(SsFieldPermVO::getSsField).collect(Collectors.toList());
        Map<String, SsFieldPermVO> fieldPermMap = listFieldPerm.stream()
                .distinct()
                .filter(item -> StrUtil.isNotBlank(item.getSsField()))
                .collect(Collectors.toMap(SsFieldPermVO::getSsField, item -> item));

        column.forEach(item -> {
            if (CollUtil.contains(fieldPerm, item.getFieldCode())) {
                if (StrUtil.isBlank(fieldPermMap.get(item.getFieldCode()).getSsOrder()) || StrUtil.equalsIgnoreCase(fieldPermMap.get(item.getFieldCode()).getSsOrder(), MdmConstant.STR_NULL)) {
                    item.setSsOrder(StrUtil.toString(Integer.MAX_VALUE));
                } else {
                    item.setSsOrder(StrUtil.toString(fieldPermMap.get(item.getFieldCode()).getSsOrder()));
                }
            } else {
                item.setSsOrder(StrUtil.toString(Integer.MAX_VALUE));
            }
        });
        List<DictFieldVO> columnSort = column.stream().sorted(Comparator.comparing(DictFieldVO::getSsOrder)).collect(Collectors.toList());

        List<String> fields = listFieldPerm.stream()
                .filter(item -> StrUtil.equalsIgnoreCase(item.getSsBrowse(), StatusWhetherEnum.STATUS_Y.getStatusCode()))
                .map(SsFieldPermVO::getSsField)
                .collect(Collectors.toList());
        Map<String, SsFieldPermVO> fieldsMap = listFieldPerm.stream().collect(Collectors.toMap(SsFieldPermVO::getSsField, Function.identity()));

        for (DictFieldVO vo : columnSort) {
            if (CollUtil.contains(foreignList, vo.getFieldCode())) {
                vo.setFkTableName(foreignMap.get(vo.getFieldCode()).getFkTableName());
                vo.setFkColumnName(foreignMap.get(vo.getFieldCode()).getFkColumnName());
            }
            vo.setSsBrowse(fieldsMap.get(vo.getFieldCode()).getSsBrowse());
            vo.setSsEdit(fieldsMap.get(vo.getFieldCode()).getSsEdit());

            if (CollUtil.contains(fields, vo.getFieldCode())) {
                filterCodeOrDesc(dictFieldDTO, result, vo);
            }

            // 字段存在外键时，新增一条其描述字段
            if (showForeign && CollUtil.contains(foreignList, vo.getFieldCode()) && CollUtil.contains(fields, vo.getFieldCode())) {
                dealForeignKey(result, foreignMap, vo);
            }
        }
        return result;
    }

    private void dealForeignKey(List<DictFieldVO> result, Map<String, TableForeignKey> foreignMap, DictFieldVO vo) {
        DictFieldVO fieldVO = new DictFieldVO();
        fieldVO.setFieldCode(buildForeignDescField(vo.getFieldCode()));
        fieldVO.setFieldDesc(vo.getFieldDesc() + "描述");
        String fkTableName = foreignMap.get(vo.getFieldCode()).getFkTableName();
        fieldVO.setTableName(fkTableName);
        fieldVO.setCurrTable(StatusWhetherEnum.STATUS_N.getStatusCode());
        result.add(fieldVO);
    }

    private String buildForeignDescField(String code) {
        return StrUtil.removeSuffixIgnoreCase(code, "Code") + "Desc";
    }


}
